﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SecurityFoundation.Entities;
using SecurityFoundation.Data;

namespace SecurityFoundation
{
    public class Constant
    {
        public const string ADMIN_ROLE = "ADMIN";
    }

    public class Repository
    {
        private static ApplicationDefination[] _applications;
        public static ApplicationDefination[] Applications
        {
            get
            {
                if (_applications == null)
                {
                   TList<ApplicationDefination> appList = DataRepository.ApplicationDefinationProvider.GetAll();

                   if (appList != null)
                       _applications = appList.ToArray();
                }

                return _applications;
            }
        }

        public static bool RefreshApplicationCache()
        {
            _applications = null;

            if (Applications != null) return true;
            else
                return false;
        }
        
        private static Realm[] _realms;
        public static Realm[] Realms
        {
            get
            {
                if (_realms == null)
                {
                    TList<Realm> realmList = DataRepository.RealmProvider.GetAll();
                    if (realmList != null)
                    {
                        _realms = realmList.ToArray();
                    }
                }

                return _realms;
            }
        }

        public static bool RefreshRealmCache()
        {
            _realms = null;

            if (Realms != null) return true;
            else
                return false;
        }

        public static ApplicationDefination GetApplicationDefinition(Guid applicationKey )
        {
            return GetApplicationDefinition(applicationKey, false);
        }

        public static ApplicationDefination GetApplicationDefinition(Guid applicationKey, bool requireObject)
        {
            ApplicationDefination app = null;

            if (Applications != null)
            {
                foreach (ApplicationDefination def in Applications)
                {
                    if (def.ApplicationKey == applicationKey)
                    {
                        app = def;
                        break;
                    }
                }
            }


            if (app == null)
            {
                // app not found.  load from database and refresh cache if it is found in db.
                app = DataRepository.ApplicationDefinationProvider.GetByApplicationKey(applicationKey);

                if (app == null) return null;
                else
                {
                    RefreshApplicationCache();
                }
            }

            

            if (app.ObjectDefinitionCollection == null || app.ObjectDefinitionCollection.Count == 0)
            {
                if (requireObject)
                {
                    TList<ObjectDefinition> objs = DataRepository.ObjectDefinitionProvider.GetByApplicationKey(app.ApplicationKey);

                    if (objs != null && objs.Count > 0)
                    {
                        app.ObjectDefinitionCollection = new TList<ObjectDefinition>();
                        foreach (ObjectDefinition ode in objs)
                        {
                            app.ObjectDefinitionCollection.Add(ode);
                        }
                    }
                }
            }

            return app;
        }

        public static ObjectDefinition[] GetApplicationObjects(Guid applicationKey, string category)
        {
            ApplicationDefination app = null;

            if (Applications != null)
            {
                foreach (ApplicationDefination def in Applications)
                {
                    if (def.ApplicationKey == applicationKey)
                    {
                        app = def;
                        break;
                    }
                }
            }


            if (app == null)
            {
                // app not found.  load from database and refresh cache if it is found in db.
                app = DataRepository.ApplicationDefinationProvider.GetByApplicationKey(applicationKey);

                if (app == null) return null;
                else
                {
                    RefreshApplicationCache();
                }
            }

            

            if (app.ObjectDefinitionCollection == null || app.ObjectDefinitionCollection.Count == 0)
            {
                TList<ObjectDefinition> objs = DataRepository.ObjectDefinitionProvider.GetByCategory(applicationKey, category);

                if (objs != null && objs.Count > 0)
                {
                    return objs.ToArray();

                }
                else
                    return null;

            }
            else
            {
                List<ObjectDefinition> defs = new List<ObjectDefinition>();

                foreach (ObjectDefinition od in app.ObjectDefinitionCollection)
                {
                    if (od.ObjectCategory == category)
                    {
                        defs.Add(od);
                    }
                }

                return defs.ToArray();
            }
        }

        public static Realm GetRealm(Guid realmKey)
        {

            if (Realms != null)
            {
                foreach (Realm r in Realms)
                {
                    if (r.RealmId == realmKey)
                        return r;
                }
            }

            // realm not found.  load from database and refresh static cache if it is found in db
            Realm rr = DataRepository.RealmProvider.GetByRealmId(realmKey);

            if (rr != null) RefreshRealmCache();

            return rr;
        }

        public static SecurityToken GetToken(Guid tokenKey)
        {
            return DataRepository.SecurityTokenProvider.GetByTokenKey(tokenKey);
        }

        public static Guid CreateToken(string application, string userName)
        {
            Guid ret = new Guid();

            ApplicationDefination app = GetApplicationDefinition(new Guid(application));

            TList<SecurityToken> existings = DataRepository.SecurityTokenProvider.FindByUser(app.Realm, app.ApplicationKey, userName);

            if (existings != null && existings.Count > 0)
            {
                existings[0].TokenCreated = DateTime.Now;
                DataRepository.SecurityTokenProvider.Update(existings);

                ret = existings[0].TokenKey;
            }
            else
            {
                SecurityToken newToken = new SecurityToken();

                newToken.Realm = app.Realm;
                newToken.SourceApplication = app.ApplicationKey;
                newToken.UserName = userName;
                newToken.TokenCreated = DateTime.Now;
                newToken.TokenKey = Guid.NewGuid();
                if (DataRepository.SecurityTokenProvider.Insert(newToken))
                {
                    ret = newToken.TokenKey;
                }
            }

            return ret;
        }

        public static ApplicationRoleMapping[] GetApplicationRoleMappings(Guid appKey)
        {
            ApplicationDefination app = GetApplicationDefinition(appKey);

            if (app.ApplicationRoleMappingCollection == null)
            {
                app.ApplicationRoleMappingCollection = DataRepository.ApplicationRoleMappingProvider.GetByApplicationKey(app.ApplicationKey);
            }

            return app.ApplicationRoleMappingCollection.ToArray();

        }

        public static string[] GetRealmRoleName(Guid applicationKey, string roleName)
        {
            ApplicationDefination app = GetApplicationDefinition(applicationKey);

            List<string> roles = new List<string>();

            if (roleName == Constant.ADMIN_ROLE && !String.IsNullOrEmpty(app.OwnerRole) )       // ADMIN is special role
            {
                return app.OwnerRole.Split(',');
            }


            if (app.UseRealmRole == (int) UseRealmRoleRequirement.Allways)
            {
                roles.Add(roleName);
            }
            else
            {

                ApplicationRoleMapping[] mappings = GetApplicationRoleMappings(app.ApplicationKey);

                if (mappings != null)
                {
                    foreach (ApplicationRoleMapping mapping in mappings)
                    {
                        if (mapping.RoleName == roleName)
                        {
                            roles.Add( mapping.RealmGroupName);
                            
                        }
                    }
                }

                if (roles.Count == 0 && app.UseRealmRole == (int)UseRealmRoleRequirement.Optional)
                {
                    roles.Add(roleName);
                }

            }

            if (roles.Count == 0) return null;
            else
                return roles.ToArray();

        }

        public static string[] GetRealmRoleName(Guid applicationKey, string[] roleList)
        {
            ApplicationDefination app = GetApplicationDefinition(applicationKey);

            List<string> roles = new List<string>();
            
            if (app.UseRealmRole == (int)UseRealmRoleRequirement.Allways)
            {
                return roleList;
            }
            else
            {

                if (app.ApplicationRoleMappingCollection == null)
                {
                    app.ApplicationRoleMappingCollection = DataRepository.ApplicationRoleMappingProvider.GetByApplicationKey(app.ApplicationKey);
                }


                if (app.ApplicationRoleMappingCollection != null)
                {
                    string role1 = String.Empty;

                    foreach (string roleName in roleList)
                    {
                        bool bFound = false;
                        foreach (ApplicationRoleMapping mapping in app.ApplicationRoleMappingCollection)
                        {
                            if (mapping.RoleName == roleName)
                            {
                                roles.Add( mapping.RealmGroupName);

                                bFound = true;
                            }
                        }

                        if ((!bFound) && app.UseRealmRole == (int)UseRealmRoleRequirement.Optional)
                        {
                            roles.Add(roleName);
                        }
                    }

                    
                }
                else if (app.UseRealmRole == (int)UseRealmRoleRequirement.Optional)
                {
                    return roleList;
                }
            }


            if (roles.Count == 0) return null;
            else
                return roles.ToArray();

        }

        public static ObjectAcl[] GetObjectAcl(Guid applicationKey, string objectName)
        {
            ObjectDefinition obj = GetObjectDefinition(applicationKey, objectName);

            if (obj == null) return null;

            TList<ObjectAcl> list = DataRepository.ObjectAclProvider.GetByObjectId(obj.ObjectId);

            if (list != null) return list.ToArray();
            else
                return null;
        }

        public static ObjectDefinition GetObjectDefinition(Guid applicationKey, string objectName)
        {
            ApplicationDefination app = GetApplicationDefinition(applicationKey, true);

            if (app == null)
                return null;

            //if (app.ObjectDefinitionCollection == null || app.ObjectDefinitionCollection.Count == 0)
            //{
            //    app.ObjectDefinitionCollection = DataRepository.ObjectDefinitionProvider.GetByApplicationKey(app.ApplicationKey);
            //}

            if( app.ObjectDefinitionCollection == null || app.ObjectDefinitionCollection.Count == 0)
                return null;

            foreach (ObjectDefinition obj in app.ObjectDefinitionCollection)
            {
                if (obj.ObjectName == objectName) return obj;
            }

            return null;
        }

        public static FieldDefinition[] GetObjectFields(Guid applicationKey, string objectName)
        {
            ObjectDefinition obj = GetObjectDefinition(applicationKey, objectName);

            if (obj != null)
            {
                TList<FieldDefinition> fields = DataRepository.FieldDefinitionProvider.GetByObjectId(obj.ObjectId);
                return fields.ToArray();
            }
            else
                return null;
        }

        public static FieldDefinition GetFieldDefinition(Guid applicationKey, string objectName, string fieldName)
        {
            ObjectDefinition obj = GetObjectDefinition(applicationKey, objectName);

            if (obj != null)
            {
                TList<FieldDefinition> fields = DataRepository.FieldDefinitionProvider.GetByObjectId(obj.ObjectId);

                if (fields != null)
                {
                    foreach (FieldDefinition field in fields)
                    {
                        if (field.FieldName == fieldName) return field;
                    }
                }
            }

            return null;
        }

        public static FieldAcl[] GetFieldAcl(Guid applicationKey, string objectName, string fieldName)
        {
            FieldDefinition field = GetFieldDefinition(applicationKey, objectName, fieldName);

            if (field == null) return null;

            TList<FieldAcl> list = DataRepository.FieldAclProvider.GetByFieldId(field.FieldId);

            if (list != null) return list.ToArray();
            else
                return null;
        }


        public static string ValidUserToken(Guid applicationKey, string userToken)
        {
            ApplicationDefination app = GetApplicationDefinition(applicationKey);
            
            SecurityToken token = DataRepository.SecurityTokenProvider.GetByTokenKey(new Guid(userToken));

            if (token != null && app != null && app.Realm == token.Realm) return token.UserName;
            else
                return null;
        }

        public static bool DeleteUserToken(Guid tokenKey)
        {
            SecurityToken token = GetToken(tokenKey);
            if (token != null)
            {
                return DataRepository.SecurityTokenProvider.Delete(tokenKey);
            }

            return false;
        }

        public static UserProfileData GetUserProfileData(Guid applicationKey, string userName)
        {
            TList<UserProfileData> list = DataRepository.UserProfileDataProvider.GetByApplicationUser(applicationKey, userName);

            if (list != null && list.Count > 0)
            {
                return list[0];
            }
            else
                return null;
        }

        public static void UpdateProfileData(UserProfileData prof)
        {
            DataRepository.UserProfileDataProvider.Update(prof);
        }

        public static void InsertProfileData(UserProfileData prof)
        {
            DataRepository.UserProfileDataProvider.Insert(prof);
        }
    }
}
